package com.baymax.test.scene.demo

import android.content.Context
import android.media.MediaDataSource
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.media3.common.MediaItem
import com.baymax.test.scene.BaseScene
import com.baymax.test.scene.ExoPlayer
import com.baymax.test.scene.Player
import com.baymax.test.scene.addButton
import com.baymax.test.scene.addDFView
import com.baymax.test.scene.installLogger
import com.baymax.test.scene.internal.Downloader
import com.baymax.test.scene.internal.cache.DiskLruCache
import com.baymax.test.scene.newSceneFlexContainer
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okio.sink
import tv.danmaku.ijk.media.player.misc.IMediaDataSource
import java.io.File

class DownloadScene : BaseScene() {
    val client = OkHttpClient()
    var job: Job = Job()
    private val downloader = Downloader(Dispatchers.IO.limitedParallelism(1), client)
    @RequiresApi(Build.VERSION_CODES.M)
    override fun onCreateView(p0: LayoutInflater, p1: ViewGroup, p2: Bundle?): View {
        val diskCache = initCache(requireSceneContext())
        lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onStop(owner: LifecycleOwner) {
                super.onStop(owner)
                diskCache?.close()
            }
        })
        return p1.newSceneFlexContainer {
            val logger = installLogger(this)
            val player = addDFView(300, 300, Player(requireSceneContext()))
            var playFunc = {}
            addButton("download") {
                job.cancel()
                job = launch {
                    try {
                        val key = "m_adtv00000000000000000716751828"
                        val f = diskCache?.edit(key)
//                        async {
////                            delay(10)
////                            logger("delay play")
////                            playFunc()
//                        }
                        downloader.download2(
                            "http://183.207.248.71:80/adtv/vod/p_adtv00000000000000001306140192/m_adtv00000000000000000716751828",
                            saver = {
                                val contentLength = it.body?.contentLength() ?: 0
                                val type = it.body?.contentType()
                                val s = diskCache?.size() ?: 0
                                logger("size(${s.toMB()}) > ${diskCache?.maxSize?.toMB()} for f(${contentLength.toMB()}) / $MB),mime = ${type}")
                                logger("edit $f")
                                if (f == null) {
                                    null
                                } else {
                                    //dirty
                                    val sink = f.newOutputStream(0, false)

                                    val fis = f.getDirtyFile(0).inputStream()
                                     async {
                                        println("start play")
                                        player.start(mediaDataSource = object: IMediaDataSource{
                                            override fun close() {
                                                f.commit()
                                            }

                                            override fun readAt(
                                                position: Long,
                                                buffer: ByteArray?,
                                                offset: Int,
                                                size: Int
                                            ): Int {
                                                println("readAt $position,$offset ,$size")
                                                fis.channel.position(position)
                                                return  fis.read(buffer,offset,size)
                                            }

                                            override fun getSize(): Long {
                                               return  s
                                            }

                                        })
                                    }.invokeOnCompletion { fis.close() }
                                    sink.sink()
                                }
                            }
                        )
                        println("f : $f")
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
            }
            addButton("cancel") {
                job.cancel()
            }
            addButton("clear cache") {
                diskCache?.remove("m_adtv00000000000000000716751828")
            }

            addButton("readFile") {
                val e = diskCache?.get("m_adtv00000000000000000716751828")
                logger("$e ,${e?.getFile(0)}")
            }


            playFunc = {
                val e = diskCache?.get("m_adtv00000000000000000716751828")
                e?.getFile(0)?.let {
                    player.start(it.absolutePath)
                }
            }
            addButton("play", onclick = { playFunc() })
            val exo = addDFView(300,300 , ExoPlayer(requireActivity()))
            addButton("exo player"){
                val e = diskCache?.get("m_adtv00000000000000000716751828")
                e?.getFile(0)?.let {
                    exo.start(it.absolutePath)
                }
            }
        }
    }

    private fun initCache(context: Context): DiskLruCache? {
        try {
            val dir = File(context.externalCacheDir, "videoCache")
            if (!dir.exists()) {
                dir.mkdirs()
            }
            val freesSpace = dir.freeSpace
            if (freesSpace > 6 * _100MB) {
                Log.i(TAG, String.format("init cache  size(%s) > 600MB", freesSpace))
                return DiskLruCache.open(dir, 1, 1, 150L * MB)
            } else if (freesSpace >= 5 * _100MB) {
                Log.i(TAG, String.format("init cache  size(%s) > 500MB", freesSpace))
                return DiskLruCache.open(dir, 1, 1, 100L * MB)
            } else {
                val exist = DiskLruCache.open(dir, 1, 1, 1L * MB)
                exist.delete()
                Log.i(TAG, String.format("init cache  size(%s) < 500MB", freesSpace))
            }
        } catch (e: Exception) {
            Log.w(TAG, "init cache error %s", e)
        }
        return null

    }

    companion object {
        const val TAG = "VideoCache"
        const val KB: Int = 1024
        const val MB: Int = 1024 * KB
        const val _100MB = 100L * MB

        fun Long.toMB(): String = "${this.toDouble() / MB}MB"
    }

}